#include <windows.h>

#include "webservice.h"

#include <tchar.h>

using namespace std;

void _stdcall CallBack(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
HANDLE hConnectedEvent, hRequestOpenedEvent, hRequestCompleteEvent;


WebService::WebService(const wstring& Server, bool IsSecure, const wstring& Method, const wstring& Headers) :
	m_sServer(Server),
	m_bSecure(IsSecure),
	m_sMethod(Method),
	m_sHeaders(Headers),
	conn(NULL),
	session(NULL)
{
}

WebService::~WebService()
{
	if (session) {
		WinHttpCloseHandle(session);
		session = NULL;
	}

	if (conn) {
		WinHttpCloseHandle(conn);
		conn = NULL;
	}
}

bool WebService::Call(wstring& Response, std::wstring sURL, std::string sPostData)
{
	if (!conn)
	{
		conn = WinHttpOpen(L"Casino", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
		if(!conn)
		{
			UDEBUGMSG((TEXT("Error in Web Service (WinHttpOpen func): %s%s"), m_sServer.c_str(), sURL.c_str()));
			return false;
		}

		session = WinHttpConnect(
				conn, 
				m_sServer.c_str(),
				m_bSecure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
				0);
		if(!session)
		{
			UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpConnect func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
			WinHttpCloseHandle(conn);
			return false;
		}
	}

	if (!session)
	{
		session = WinHttpConnect(
				conn, 
				m_sServer.c_str(),
				m_bSecure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
				0);
		if(!session)
		{
			UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpConnect func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
			WinHttpCloseHandle(conn);
			return false;
		}
	}

	UDEBUGMSG((TEXT("Web Service call: %s%s"), m_sServer.c_str(), sURL.c_str()));

	DWORD dRequestFlags = WINHTTP_FLAG_REFRESH;
	dRequestFlags =	m_bSecure ? dRequestFlags | WINHTTP_FLAG_SECURE : dRequestFlags;
	HINTERNET httpRequest = WinHttpOpenRequest(
		session, m_sMethod.c_str(), sURL.c_str(), NULL, NULL, NULL, dRequestFlags);
	if(!httpRequest)
	{
		UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpOpenRequest func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
		WinHttpCloseHandle(session);
		WinHttpCloseHandle(conn);
		conn = NULL;
		session = NULL;
		return false;
	}	

	if(!WinHttpAddRequestHeaders(httpRequest, (LPCWSTR)m_sHeaders.c_str(), m_sHeaders.length(), WINHTTP_ADDREQ_FLAG_ADD))
	{
		UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpAddRequestHeaders func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
		WinHttpCloseHandle(httpRequest);
		WinHttpCloseHandle(session);
		WinHttpCloseHandle(conn);
		return false;
	}
	
	// Do we have any POST data to send?
	BOOL bSendResult = FALSE;
	if (sPostData.empty())
	{
		bSendResult = WinHttpSendRequest(httpRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
	}
	else
	{
		bSendResult = WinHttpSendRequest(httpRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)sPostData.c_str(), sPostData.length(), sPostData.length(), 0);
	}
	
	if(!bSendResult)
	{
		UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpSendRequest func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
		WinHttpCloseHandle(httpRequest);
		WinHttpCloseHandle(session);
		WinHttpCloseHandle(conn);
		httpRequest = NULL;
		conn = NULL;
		session = NULL;
		return false;
	}

	// End the request.
	if(!WinHttpReceiveResponse( httpRequest, NULL))
	{
		UDEBUGMSG((TEXT("Error calling %s%s Web Service (WinHttpSendRequest func). Error: %d"), m_sServer.c_str(), sURL.c_str(), GetLastError()));
		WinHttpCloseHandle(httpRequest);
		WinHttpCloseHandle(session);
		WinHttpCloseHandle(conn);
		httpRequest = NULL;
		conn = NULL;
		session = NULL;
		return false;
	}	

#ifdef DEBUG

	// Read HTTP response status code
	DWORD dwStatusCode = 0;
	DWORD dwTemp = sizeof(dwStatusCode);
	WinHttpQueryHeaders(httpRequest, WINHTTP_QUERY_STATUS_CODE| WINHTTP_QUERY_FLAG_NUMBER,
	                    NULL, &dwStatusCode, &dwTemp, NULL);

#endif

	// Read server response
	DWORD dwBytesAvailable = 0;
	String sResponse = "";
	WinHttpQueryDataAvailable(httpRequest, &dwBytesAvailable);
	if (dwBytesAvailable)
	{
		do
		{
			char *pMessageBody = new char[dwBytesAvailable+1];

			DWORD dwBytesRead;
			if(!WinHttpReadData(httpRequest, pMessageBody, dwBytesAvailable, &dwBytesRead))
			{
				delete pMessageBody;
				break;
			}

			if (dwBytesRead == 0)
			{
				delete pMessageBody;
				break;	// End of File.
			}

			pMessageBody[dwBytesRead] = '\0';

			// Convert to wide char to deal with UTF8 strings
			int wchars_num = MultiByteToWideChar(CP_UTF8, 0, pMessageBody, -1, NULL, 0);
			wchar_t* wstr = new wchar_t[wchars_num];
			MultiByteToWideChar(CP_UTF8, 0, pMessageBody, -1, wstr, wchars_num);

			sResponse = sResponse + String(wstr);
			delete[] pMessageBody;
			delete wstr;

			WinHttpQueryDataAvailable(httpRequest, &dwBytesAvailable);

		} while (dwBytesAvailable);
	}

	// Convert response to std::wstring
	Response = sResponse;

	WinHttpSetStatusCallback(httpRequest, NULL, 0, 0);
	WinHttpCloseHandle(httpRequest);
	
	return true;
	
};

wstring WebService::GetServer() const
{
	return m_sServer;
};

void WebService::SetServer(const wstring& Server)
{
	m_sServer=Server;
};

wstring WebService::GetMethod() const
{
	return m_sMethod;
};

void WebService::SetMethod(const wstring& Method)
{
	m_sMethod=Method;
};

wstring WebService::GetHeaders() const
{
	return m_sHeaders;
};

void WebService::SetHeaders(const wstring& Headers)
{
	m_sHeaders=Headers;
};





